﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//操作符（运算符）

//算数操作符
/*1. 除了 % 操作符之外，其他的几个操作符可以作用于整数和浮点数。
2. % 操作符的两个操作数必须为整数。返回的是整除之后的余数*/

//int main()
//{
//	printf("%d", 10 / 5);  //2
//	printf("%d", 10 % 5);  //0
//	printf("%lf", 10 / 3.0);  //3.333333
	/*对于 / 操作符如果两个操作数都为整数，执行整数除法。而只要有浮点数执行的就是浮点数除法*/
//	return 0;
//}

//移位操作符-------移动的是二进制的位
//<< 左移操作符
//>> 右移操作符
//注：移位操作符的操作数只能是整数。

//16进制的数据中：都是0~15的数字组成---0 1 2 3 4 5 6 7 8 9 a b c d e f
//10进制的数据中：都是0~9的数字组成
//8进制的数据中：都是0~7的数字组成
//2进制的数据中：都是0~1的数字组成
//2、8、10、16进制只不过是数值的表示形式而言

//整数的二进制表示形式3种：原码、反码、补码

//原码：把一个数按照正负直接翻译成二进制就是原码
// 反码：原码符号位（最高位）不变，其他位按位取反（0变1，1变0）
// 补码：反码+1
//eg.原码 5 （整数，整数是存放在整型变量中的，一个整型变量是4个字节-32比特位）          ------00000000000000000000000000000101
//原码 -5     -------10000000000000000000000000000101
// 反码 -5     -------11111111111111111111111111111010
// 补码 -5     -------11111111111111111111111111111011
//最高一位表示符号位，0表示正数，1表示负数

//正整数的原码，反码，补码是相同的
//负整数的原码，反码，补码要计算

//整数在内存中存储的是二进制的补码

//int main()
//{
//	int a = 3;
//	//00000000000000000000000000000011
//	int b = a << 1;
//	//00000000000000000000000000000110,左移1位相当于丢弃头，尾用0填充
//	printf("%d\n", b);  //6
//	printf("%d\n", a);  //3
//}

//首先右移运算分两种：
//1. 逻辑移位
//左边用0填充，右边丢弃
//2. 算术移位
//左边用原该值的符号位填充（正数补0，负数补1），右边丢弃
//逻辑移位or算术移位由编译器决定
//对于移位运算符，不要移动负数位，这个是标准未定义的

//位操作符
//& //按位与
//| //按位或
//^ //按位异或
//注：他们的操作数必须是整数

//int main()
//{
//	int a = 3;
//	int b = -5;
//	int c = a & b;//有0为0，全1为1
//	//3的补码  00000000000000000000000000000011
//	//-5的补码 11111111111111111111111111111011
//	//a&b            00000000000000000000000000000011(需要把补码转换为原码，因为结果为正数，所有原码和补码相同）
//	printf("%d", c);  //3
//	int c = a | b;  //有1为1，全0为0
//	//3的补码  00000000000000000000000000000011
//	//-5的补码 11111111111111111111111111111011
//	// a | b          11111111111111111111111111111011
//	//补码转原码  ----10000000000000000000000000000101
//	printf("%d", c);  //-5
//	int c = a ^ b;  //按位异或-对应的二进制位，相同为0，相异为1
//	//3的补码  00000000000000000000000000000011
//	//-5的补码 11111111111111111111111111111011
//	// a ^ b        11111111111111111111111111111000
//	//补码转原码  ----11111111111111111111111111110111,10000000000000000000000000001000
//	printf("%d", c);  //-8
//	return 0;
//}

//一道变态的面试题：
//不能创建临时变量（第三个变量），实现两个数的交换
//int main()
//{
//	int a = 10;
//	int b = 20;
//	a = a+b;
//	b = a-b;
//	a = a-b;
//	printf("a = %d b = %d\n", a, b);
//	return 0;
//}//这样写有问题，如果a,b足够大会造成溢出，只能解决一些合适的数据
////以下这种写法就没问题
// a^a=0,0^a=a,   ^也支持交换律，可以举例计算
//int main()
//{
//	int a = 10;
//	int b = 20;
//	a = a ^ b;   
//	b = a ^ b;  //a^b^b=a^0=a
//	a = a ^ b;  //a^b^a=b^0=0
//	printf("a = %d b = %d\n", a, b);
//	return 0;
//}

//赋值操作符
//int weight = 120;//体重
//weight = 89;//不满意就赋值
//double salary = 10000.0;
//salary = 20000.0;//使用赋值操作符赋值
//赋值操作符可以连续使用，比如：
//int a = 10;
//int x = 0;
//int y = 20;
//a = x = y + 1;//连续赋值
//这样的代码感觉怎么样？
//那同样的语义，你看看：
//x = y + 1;
//a = x;
//这样的写法是不是更加清晰爽朗而且易于调试

//单目操作符
//int main()
//{
//	int flag = 5;
//	if (flag)  //flag为真做什么
//	{
//
//	}
//	if (!flag) //flag为假做什么
//	{
//
//	}
//	return 0;
//}

//int main()
//{
//	int a = 10;
//	int* p=&a; //&取地址操作符
// *p=20; // 解引用操作符（间接访问操作符）
// printf("%d", a);  //a的值变为20
//	int arr[10];
//	&arr; //取出数组的地址
//}

//int main()
//{
//	int a = -10;
//	int* p = NULL;
//	printf("%d\n", !2);
//	printf("%d\n", !0);
//	a = -a;
//	p = &a;
//	printf("%d\n", sizeof(a));
//	printf("%d\n", sizeof(int));
//	printf("%d\n", sizeof a);//这样写行不行？行
//	//printf("%d\n", sizeof int);//这样写行不行？不行
//	return 0;
//}

//~    对一个数的二进制按位取反
//int main()
//{
//	int a = 0;
//	//a---00000000000000000000000000000000
//	//~a-----11111111111111111111111111111
//	//补码转原码---10000000000000000000000000000001
//	printf("%d", ~a); //-1
//}

//int main()
//{
//	float a = 3.14f;
//	int b = (int)a;  //强制类型转换，类型最终是不会改变的，一般不太合适
//}

//void test1(int arr[])  //int*
//{
//	printf("%d\n", sizeof(arr));//传过来的是数组首地址,4
//}
//void test2(char ch[])   //char*
//{
//	printf("%d\n", sizeof(ch));//4
//}
//int main()
//{
//	int arr[10] = { 0 };
//	char ch[10] = { 0 };
//	printf("%d\n", sizeof(arr));//(1)   40
//	printf("%d\n", sizeof(ch));//(3)   10
//	test1(arr);
//	test2(ch);
//	return 0;
//} 

//区分逻辑与和按位与
//区分逻辑或和按位或
//	&& 逻辑与
//	|| 逻辑或
//	1 & 2----->0
//	1 && 2---->1
//	1 | 2----->3
//	1 || 2---- > 1

//int main()
//{
//	int i = 0, a = 0, b = 2, c = 3, d = 4;
//	i = a++ && ++b && d++;
//	//i = a++||++b||d++;
//	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
//	//1 2 3 4(因为a++先赋值为0，所有i为假，后续不用算了
//	return 0;
//}
//int main()
//{
//	int i = 0, a = 1, b = 2, c = 3, d = 4;
//	i = a++ && ++b && d++;
//	//i = a++||++b||d++;
//	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
//	//2 3 3 5
//	return 0;
//}
//int main()
//{
//	int i = 0, a = 1, b = 2, c = 3, d = 4;
//	i = a++||++b||d++;//a++为1，i恒为真，后续不用算了
//	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
//	//2 2 3 4
//	return 0;
//}
//int main()
//{
//	int i = 0, a = 0, b = 2, c = 3, d = 4;
//	i = a++ || ++b || d++;
//	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
//	//1 3 3 4
//	return 0;
//}

//作业
//int main()
//{
//	int a, b, c;
//	a = 5;
//	c = ++a;  
//	b = ++c, c++, ++a, a++;
//	b += a++ + c;
//	printf("a = %d b = %d c = %d\n:", a, b, c); //9 23 8
//	return 0;
//}

//统计二进制中1的个数
//int main()
//{
//	int num = 0;
//	scanf("%d", &num);
//	int i = 0;
//	int count = 0;//计数
//	for (i = 0; i < 32; i++)  //左移32次
//	{
//		if (num & (1 << i))  //若按位与结果为1，则该位为1
//			count++;
//	}
//	printf("二进制中1的个数 = %d\n", count);
//	return 0;
//}

//获取一个整数二进制序列中所有的偶数位和奇数位，分别打印出二进制序列
//int main()
//{
//	int a = 0;
//	scanf("%d", &a);
//	int i = 0;
//	printf("偶数位：");
//	for (i = 31; i >= 1; i -= 2) //偶数
//	{
//		printf("%d", (a >> i) & 1);
//	}
//	printf("\n");
//	printf("奇数位：");
//	for (i = 30; i >= 0; i -= 2) //奇数
//	{
//		printf("%d", (a >> i) & 1);
//	}
//	printf("\n");
//	system("pause");
//	return 0;
//}

//编程实现：两个int（32位）整数m和n的二进制表达中，有多少个位(bit)不同？
//输入例子 :
//1999 2299
//输出例子 : 7
//int main()
//{
//	int a, b,count=0;
//	scanf("%d %d", &a, &b);
//	int c = a ^ b;  //相同为0，相异为1
//	while (c)
//	{
//		c = c & (c - 1);
//		count++;
//	}
//	printf("%d", count);
//}